# i-learn-express-validator

Учусь и тестирую как работать с express-validator.

## Цели проекта

### Научиться:

1. Запуск express сервера.
2. Валидация получаемых от пользователя данных.
3. Одновременное использование 2 и более БД.
4. Регистрация новых пользователей.
5. Аутентификация пользователей по токену.
6. Вывод пользователю данных о нем.
7. Запись и изменение данных о студентах в БД.
8. Вывод данных о студентах из БД.
9. Использование переменных среды.

### Использовать библиотеки:

#### dotenv

1. Хранение номеров портов, ключей, паролей, токенов и тд. в переменных среды.

#### express

1. Запуск сервера.
2. Обработка GET и POST запросы от пользователя.

#### express-validator

1. Создание правил валидации.
2. Валидация полученных данных от пользователя в формате json на соответствие правилам.

#### mongoose

1. Подключение к 2 БД.
2. Создание моделей пользователя и студента.
3. Создание документов нового студента или пользователя, на основе моделей, из данных прошедших валидацию.
4. Загрузка документов в БД.
5. Чтение документов из БД.

#### jsonwebtoken

1. Генерация токена авторизации

## План | Конспект

### Переменные среды .env

Хранить в переменных среды следующие данные:

1. Номер порта для работы сервера.
2. Токен для подключения к БД пользователей.
3. Токен для подключения к БД студентов.
4. Секрет Json Web Token.

Хранить .example файл переменных среды в репозитории проекта.

### index.js

1. Получить номер порта из переменных среды.
2. Запустить сервер. Вывести сообщение в консоль об успешном запуске сервера или ошибку.
3. Обработчики:
    - GET /
    - POST /auth/register
    - POST /auth/login
    - POST /students
    - POST /students/new

#### Обработчик GET запросов на _*/*_

Обработчик GET для теста доступности сервера из через браузер из LAN и WAN.

1. Принимаем GET запрос на адрес _*ADDRESS:SERVER_PORT/*_
2. Выводим в консоль информацию о получении GET запроса.
3. Отправляем пользователю код 200 + сообщение.

#### Обработчик POST запросов на _*/auth/register*_

Обработчик POST запросов на регистрацию новых пользователей.

1. Принимаем POST запрос от пользователя на _*ADDRESS:SERVER_PORT/auth/register*_ c данными:
    - _userEmail_,
    - _userRealName_,
    - _userPassword_,
    - _userAvatarURL_
2. Передаем объект _newUserValidator_ с инструкциями для валидации.
3. Валидируем полученный json методом _validationResult_.
4. Если данные не соответствуют требованиям:
    - Возвращаем пользователю код 400 + json информацию об ошибке.
5. Если данные соответствуют требованиям:
    - Создаем документ пользователя _userDoc_ на основе модели _UserModel_.
    - Загружаем документ пользователя _userDoc_ в БД пользователей.
    - Если ошибка записи документа в БД:
        - Выводим ошибку в консоль.
        - Возвращаем пользователю код 400 + json с сообщением о том что не удалось зарегистрироваться.
    - Если документ успешно записан в БД:
        - Генерируем JWT токен авторизации _userToken_.
        - Реструктурируем _user.\_doc_ и создаем объект пользователя только без графы пароля _userData_.
        - Возвращаем пользователю код 200 + _userToken_ + _userData_.
        - Выводим в консоль сообщение о том что новый пользователь зарегистрирован + _userData.userEmail_.

#### Обработчик POST запросов на _*/auth/login*_

1. Принимаем POST запрос от пользователя на _*ADDRESS:SERVER_PORT/auth/login*_ c данными:
    - _userEmail_,
    - _userPassword_
2. Выполняем поиск пользователя с таким _userEmail_ в БД пользователей.
3. Если ошибка с БД:
    - Возвращаем пользователю код 500 + json с сообщением о том что произошла ошибка авторизации.
4. Если пользователь не найден:
    - Возвращаем пользователю код 400 + json с сообщением о том что такой пользователь не зарегистрирован.
5. Если пользователь найден:
    - Проверяем совпадает ли переданный пользователем userPassword с userPassword из БД.
    - Если пароль не совпадает:
        - Выводим ошибку в консоль.
        - Возвращаем пользователю код 400 + json с сообщением о том что пароль не верный.
    - Если пароль совпадает:
        - Генерируем JWT токен авторизации _userToken_.
        - Реструктурируем полученный из БД _user.\_doc_ и создаем объект пользователя только без графы пароля _userData_.
        - Возвращаем пользователю код 200 + _userToken_ + _userData_.
        - Выводим в консоль сообщение о том что новый пользователь авторизовался + _userData.userEmail_.

#### Обработчик POST запросов на _*/students/new*_

1. Принимаем POST запрос от пользователя на _*ADDRESS:SERVER_PORT/students/new*_ c данными:
    - _studentRealName_,
    - _studentEnglishName_,
    - _studentBirthDate_,
    - _userAvatarURL_
2. Передаем объект _newStudentValidator_ с инструкциями для валидации.
3. Валидируем полученный json методом _validationResult_.
4. Если данные не соответствуют требованиям:
    - Возвращаем пользователю код 400 + json информацию об ошибке.
5. Если данные соответствуют требованиям:
    - Создаем документ студента _studentDoc_ на основе модели _StudentModel_.
    - Загружаем документ студента _studentDoc_ в БД студентов.
    - Если ошибка записи документа в БД:
        - Выводим ошибку в консоль.
        - Возвращаем пользователю код 400 + json с сообщением о том что не удалось записать нового студента.
    - Если документ успешно записан в БД:
        - Возвращаем пользователю код 200 + _studentDoc_.
        - Выводим в консоль сообщение о том что новый студент добавлен + _studentDoc.studentRealName_ + studentDoc.studentEnglishName.

### express-validator

#### Валидатор _newUserValidator_

Валидировать полученный json на соответствие условиям:

1. userEmail - обязательное поле, уникальное значение, isEmail();
2. userRealName - обязательное поле, строка 1-30 символов;
3. userPassword - обязательное поле, строка 5-30 символов;
4. userAvatarURL - опциональное поле, isURL().

#### Валидатор _newStudentValidator_

Валидировать полученный json на соответствие условиям:

1. studentRealName - обязательное поле, строка 1-30 символов;
2. studentEnglishName - обязательное поле, только латинские буквы и цифры, строка 1-30 символов;
3. studentBirthDate - опциональное поле, isISO8601().toDate();
4. studentPhotoURL - опциональное поле, isURL().

## Описание

### Переменные среды

Переменные среды, такие как токен для подключения к базе данных, номера портов и тд. должны храниться в файле **_.env_** к в проекте присутствует файл **_.env.example_** необходимо переименовать его в **_.env_** и вписать все необходимые переменные.

### index.js

#### Импорты:

Импортируем в проект express.
Импортируем метод config из dotenv - подключает переменные среды.
Импортируем метод validationResult из express-validator.
Импортируем в проект mongoose - для работы с mongodb.
Импортируем объект newUserValidator с инструкциями для дальнейшей валидации из validation-new-user.js
Импортируем объект newStudentValidator с инструкциями для дальнейшей валидации из validation-new-student.js
Импортируем переменные userConnection и studentConnection с объектами подключения к БД из db.js
Импортируем в проект Json Web Token для работы с токенами аутентификации.
Импортируем модель студента для загрузки создания документов для дальнейшей загрузки в БД

#### Обработчик GET запросов на _*/*_

Обработчик GET для теста доступности сервера из через браузер из LAN и WAN.
Принимаем GET запрос на адрес **_address:SERVER_PORT_** в случае если запрос получен выводим информацию в консоль и отправляем пользователю сообщение.

#### Обработчик POST запросов на _*/auth/register*_

Принимаем POST запрос от пользователя на **_localhost:SERVER_PORT/_** передаем объект с инструкциями для валидации. Валидируем полученный json методом validationResult кладем результат в переменную errors. Дальше если errors пустой метод isEmpty передаст true с помощью логического отрицания ! мы по итогу получим false. Если ошибки есть false превратится в true и тогда мы передадим сообщение в консоль о том что данные не соответствуют требованиям, а пользователю передадим данные об ошибке. Ошибок нет выведем в консоль сообщение о том что данные прошли валидацию. А пользователю передадим сообщение об успешной регистрации.

#### Обработчик POST запросов на _*/student/new*_

Принимаем POST запрос от пользователя на **_localhost:SERVER_PORT/student/new_** валидируем полученные данные.Если валидация проходит успешно тогда создаем документ нового студена studentDoc на основе модели StudentModel. Загружаем данные в базу данных студентов асинхронной функцией.

#### Express сервер:

Express запускает сервер и мониторит порт (номер порта хранится в переменной среды SERVER_PORT). В случае если все ОК выводим в консоль Server OK. Если возникли ошибки выводим их в консоль.

### validation-new-user.js - валидация данных нового пользователя

Импортируем функцию body из express-validator.
Создаем и экспортируем объект инструкций для express-validator в дальнейшем будет использоваться функции validationResult из express-validator.

### validation-new-student.js - валидация данных нового студента

Импортируем функцию body из express-validator.
Создаем и экспортируем объект инструкций для express-validator в дальнейшем будет использоваться функции validationResult из express-validator.

### student.js - модель данных студента

Импортируем mongoose. Импортируем переменную с объектом подключения к БД userConnection из db.js Создаем схему данных нового студента для загрузки в БД. Импортируем схему студента в качестве модели, на основе которой будет создан документ для загрузки в БД, указывая что загружаться она должна по через studentConnection

### db.js - подключение к БД

Создаем 2 разных подключения. Токены достаем из переменных среды.

```
// Токен для подключения к ДБ user из файла .env
const userDbToken = process.env.USER_DB_TOKEN;

// Токен для подключения к ДБ student из файла .env
const studentDbToken = process.env.STUDENT_DB_TOKEN;

// Подключаемся к ДБ users
const userConnection = mongoose.createConnection(userDbToken);
userConnection.on("connected", () => {
console.log("Users Database OK");
});
userConnection.on("error", (err) => {
console.log("Users Database ERROR" + err);
});

// Подключаемся к ДБ students
const studentConnection = mongoose.createConnection(studentDbToken);
studentConnection.on("connected", () => {
console.log("Students Database OK");
});
studentConnection.on("error", (err) => {
console.log("Students Database ERROR" + err);
});
```

## Тестирование

Для теста использовал программу Insomnia файл _insomnia-test.yaml_.

## Благодарность

В качестве учебного материала использовал [видео](https://www.youtube.com/watch?v=GQ_pTmcXNrQ&t=4121s/).

Cпасибо [Archakov Blog](https://www.youtube.com/@ArchakovBlog).
